home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / ip.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  13KB  |  545 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include "global.h"
  7. #include "config.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "internet.h"
  11. #include "netuser.h"
  12. #include "iface.h"
  13. #include "pktdrvr.h"
  14. #include "ip.h"
  15. #include "icmp.h"
  16.  
  17. static struct mbuf *fraghandle __ARGS((struct ip *ip,struct mbuf *bp));
  18. static void ip_timeout __ARGS((void *arg));
  19. static void free_reasm __ARGS((struct reasm *rp));
  20. static void freefrag __ARGS((struct frag *fp));
  21. static struct reasm *lookup_reasm __ARGS((struct ip *ip));
  22. static struct reasm *creat_reasm __ARGS((struct ip *ip));
  23. static struct frag *newfrag __ARGS((int16 offset,int16 last,struct mbuf *bp));
  24.  
  25. struct mib_entry Ip_mib[20] = {
  26.     "",            0,
  27.     "ipForwarding",        1,
  28.     "ipDefaultTTL",        MAXTTL,
  29.     "ipInReceives",        0,
  30.     "ipInHdrErrors",    0,
  31.     "ipInAddrErrors",    0,
  32.     "ipForwDatagrams",    0,
  33.     "ipInUnknownProtos",    0,
  34.     "ipInDiscards",        0,
  35.     "ipInDelivers",        0,
  36.     "ipOutRequests",    0,
  37.     "ipOutDiscards",    0,
  38.     "ipOutNoRoutes",    0,
  39.     "ipReasmTimeout",    TLB,
  40.     "ipReasmReqds",        0,
  41.     "ipReasmOKs",        0,
  42.     "ipReasmFails",        0,
  43.     "ipFragOKs",        0,
  44.     "ipFragFails",        0,
  45.     "ipFragCreates",    0,
  46. };
  47.  
  48. struct reasm *Reasmq;
  49. static struct raw_ip *Raw_ip;
  50.  
  51. #define    INSERT    0
  52. #define    APPEND    1
  53. #define    PREPEND    2
  54.  
  55. /* Send an IP datagram. Modeled after the example interface on p 32 of
  56.  * RFC 791
  57.  */
  58. int
  59. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  60. int32 source;            /* source address */
  61. int32 dest;            /* Destination address */
  62. char protocol;            /* Protocol */
  63. char tos;            /* Type of service */
  64. char ttl;            /* Time-to-live */
  65. struct mbuf *bp;        /* Data portion of datagram */
  66. int16 length;            /* Optional length of data portion */
  67. int16 id;            /* Optional identification */
  68. char df;            /* Don't-fragment flag */
  69. {
  70.     struct mbuf *tbp;
  71.     struct ip ip;            /* IP header */
  72.     static int16 id_cntr = 0;    /* Datagram serial number */
  73.     struct phdr phdr;
  74.  
  75.     ipOutRequests++;
  76.  
  77.     if(source == INADDR_ANY)
  78.         source = locaddr(dest);
  79.     if(length == 0 && bp != NULLBUF)
  80.         length = len_p(bp);
  81.     if(id == 0)
  82.         id = id_cntr++;        
  83.     if(ttl == 0)
  84.         ttl = ipDefaultTTL;
  85.  
  86.     /* Fill in IP header */
  87.     ip.version = IPVERSION;
  88.     ip.tos = tos;
  89.     ip.length = IPLEN + length;
  90.     ip.id = id;
  91.     ip.offset = 0;
  92.     ip.flags.mf = 0;
  93.     ip.flags.df = df;
  94.     ip.flags.congest = 0;
  95.     ip.ttl = ttl;
  96.     ip.protocol = protocol;
  97.     ip.source = source;
  98.     ip.dest = dest;
  99.     ip.optlen = 0;
  100.     if((tbp = htonip(&ip,bp,IP_CS_NEW)) == NULLBUF){
  101.         free_p(bp);
  102.         return -1;
  103.     }
  104.     if((bp = pushdown(tbp,sizeof(phdr))) == NULLBUF){
  105.         free_p(tbp);
  106.         return -1;
  107.     }
  108.     if(ismyaddr(ip.dest)){
  109.         /* Pretend it has been sent by the loopback interface before
  110.          * it appears in the receive queue
  111.          */
  112.         phdr.iface = &Loopback;
  113.         Loopback.ipsndcnt++;
  114.         Loopback.rawsndcnt++;
  115.         Loopback.lastsent = secclock();
  116.     } else
  117.         phdr.iface = NULLIF;
  118.     phdr.type = CL_NONE;
  119.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  120.     enqueue(&Hopper,bp);
  121.     return 0;
  122. }
  123.  
  124. /* Reassemble incoming IP fragments and dispatch completed datagrams
  125.  * to the proper transport module
  126.  */
  127. void
  128. ip_recv(iface,ip,bp,rxbroadcast)
  129. struct iface *iface;    /* Incoming interface */
  130. struct ip *ip;        /* Extracted IP header */
  131. struct mbuf *bp;    /* Data portion */
  132. int rxbroadcast;    /* True if received on subnet broadcast address */
  133. {
  134.     /* Function to call with completed datagram */
  135.     register struct raw_ip *rp;
  136.     struct mbuf *bp1,*tbp;
  137.     int rxcnt = 0;
  138.     register struct iplink *ipp;
  139.  
  140.     /* If we have a complete packet, call the next layer
  141.      * to handle the result. Note that fraghandle passes back
  142.      * a length field that does NOT include the IP header
  143.      */
  144.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  145.         return;        /* Not done yet */
  146.  
  147.     ipInDelivers++;
  148.  
  149.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  150.         if(rp->protocol != ip->protocol)
  151.             continue;
  152.         rxcnt++;
  153.         /* Duplicate the data portion, and put the header back on */
  154.         dup_p(&bp1,bp,0,len_p(bp));
  155.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1,IP_CS_OLD)) != NULLBUF){
  156.             enqueue(&rp->rcvq,tbp);
  157.             if(rp->r_upcall != NULLVFP((struct raw_ip *)))
  158.                 (*rp->r_upcall)(rp);
  159.         } else {
  160.             free_p(bp1);
  161.         }
  162.     }
  163.     /* Look it up in the transport protocol table */
  164.     for(ipp = Iplink;ipp->funct != NULL;ipp++){
  165.         if(ipp->proto == ip->protocol)
  166.             break;
  167.     }
  168.     if(ipp->funct != NULL){
  169.         /* Found, call transport protocol */
  170.         (*ipp->funct)(iface,ip,bp,rxbroadcast);
  171.     } else {
  172.         /* Not found */
  173.         if(rxcnt == 0){
  174.             /* Send an ICMP Protocol Unknown response... */
  175.             ipInUnknownProtos++;
  176.             /* ...unless it's a broadcast */
  177.             if(!rxbroadcast){
  178.                 icmp_output(ip,bp,ICMP_DEST_UNREACH,
  179.                  ICMP_PROT_UNREACH,NULLICMP);
  180.             }
  181.         }
  182.         free_p(bp);
  183.     }
  184. }
  185.  
  186. #ifdef ENCAP
  187. /* Handle IP packets encapsulated inside IP */
  188. void
  189. ipip_recv(iface,ip,bp,rxbroadcast)
  190. struct iface *iface;    /* Incoming interface */
  191. struct ip *ip;        /* Extracted IP header */
  192. struct mbuf *bp;    /* Data portion */
  193. int rxbroadcast;    /* True if received on subnet broadcast address */
  194. {
  195.     struct phdr phdr;
  196.     struct mbuf *tbp;
  197.  
  198.     if((tbp = pushdown(bp,sizeof(phdr))) == NULLBUF){
  199.         free_p(bp);
  200.         return;
  201.     }
  202.     bp = tbp;
  203.     phdr.iface = &Encap;
  204.     phdr.type = CL_NONE;
  205.     memcpy(&bp->data[0],(char *)&phdr,sizeof(phdr));
  206.     enqueue(&Hopper,bp);
  207. }
  208. #endif
  209.  
  210. /* Process IP datagram fragments
  211.  * If datagram is complete, return it with ip->length containing the data
  212.  * length (MINUS header); otherwise return NULLBUF
  213.  */
  214. static
  215. struct mbuf *
  216. fraghandle(ip,bp)
  217. struct ip *ip;        /* IP header, host byte order */
  218. struct mbuf *bp;    /* The fragment itself */
  219. {
  220.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  221.     struct frag *lastfrag,*nextfrag,*tfp;
  222.     struct mbuf *tbp;
  223.     int16 i;
  224.     int16 last;        /* Index of first byte beyond fragment */
  225.  
  226.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  227.  
  228.     rp = lookup_reasm(ip);
  229.     if(ip->offset == 0 && !ip->flags.mf){
  230.         /* Complete datagram received. Discard any earlier fragments */
  231.         if(rp != NULLREASM){
  232.             free_reasm(rp);
  233.             ipReasmOKs++;
  234.         }
  235.         return bp;
  236.     }
  237.     ipReasmReqds++;
  238.     if(rp == NULLREASM){
  239.         /* First fragment; create new reassembly descriptor */
  240.         if((rp = creat_reasm(ip)) == NULLREASM){
  241.             /* No space for descriptor, drop fragment */
  242.             ipReasmFails++;
  243.             free_p(bp);
  244.             return NULLBUF;
  245.         }
  246.     }
  247.     /* Keep restarting timer as long as we keep getting fragments */
  248.     stop_timer(&rp->timer);
  249.     start_timer(&rp->timer);
  250.  
  251.     /* If this is the last fragment, we now know how long the
  252.      * entire datagram is; record it
  253.      */
  254.     if(!ip->flags.mf)
  255.         rp->length = last;
  256.  
  257.     /* Set nextfrag to the first fragment which begins after us,
  258.      * and lastfrag to the last fragment which begins before us
  259.      */
  260.     lastfrag = NULLFRAG;
  261.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  262.         if(nextfrag->offset > ip->offset)
  263.             break;
  264.         lastfrag = nextfrag;
  265.     }
  266.     /* Check for overlap with preceeding fragment */
  267.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  268.         /* Strip overlap from new fragment */
  269.         i = lastfrag->last - ip->offset;
  270.         pullup(&bp,NULLCHAR,i);
  271.         if(bp == NULLBUF)
  272.             return NULLBUF;    /* Nothing left */
  273.         ip->offset += i;
  274.     }
  275.     /* Look for overlap with succeeding segments */
  276.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  277.         tfp = nextfrag->next;    /* save in case we delete fp */
  278.  
  279.         if(nextfrag->offset >= last)
  280.             break;    /* Past our end */
  281.         /* Trim the front of this entry; if nothing is
  282.          * left, remove it.
  283.          */
  284.         i = last - nextfrag->offset;
  285.         pullup(&nextfrag->buf,NULLCHAR,i);
  286.         if(nextfrag->buf == NULLBUF){
  287.             /* superseded; delete from list */
  288.             if(nextfrag->prev != NULLFRAG)
  289.                 nextfrag->prev->next = nextfrag->next;
  290.             else
  291.                 rp->fraglist = nextfrag->next;
  292.             if(tfp->next != NULLFRAG)
  293.                 nextfrag->next->prev = nextfrag->prev;
  294.             freefrag(nextfrag);
  295.         } else
  296.             nextfrag->offset = last;
  297.     }
  298.     /* Lastfrag now points, as before, to the fragment before us;
  299.      * nextfrag points at the next fragment. Check to see if we can
  300.      * join to either or both fragments.
  301.      */
  302.     i = INSERT;
  303.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  304.         i |= APPEND;
  305.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  306.         i |= PREPEND;
  307.     switch(i){
  308.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  309.         tfp = newfrag(ip->offset,last,bp);
  310.         tfp->prev = lastfrag;
  311.         tfp->next = nextfrag;
  312.         if(lastfrag != NULLFRAG)
  313.             lastfrag->next = tfp;    /* Middle of list */
  314.         else
  315.             rp->fraglist = tfp;    /* First on list */
  316.         if(nextfrag != NULLFRAG)
  317.             nextfrag->prev = tfp;
  318.         break;
  319.     case APPEND:    /* Append to lastfrag */
  320.         append(&lastfrag->buf,bp);
  321.         lastfrag->last = last;    /* Extend forward */
  322.         break;
  323.     case PREPEND:    /* Prepend to nextfrag */
  324.         tbp = nextfrag->buf;
  325.         nextfrag->buf = bp;
  326.         append(&nextfrag->buf,tbp);
  327.         nextfrag->offset = ip->offset;    /* Extend backward */
  328.         break;
  329.     case (APPEND|PREPEND):
  330.         /* Consolidate by appending this fragment and nextfrag
  331.          * to lastfrag and removing the nextfrag descriptor
  332.          */
  333.         append(&lastfrag->buf,bp);
  334.         append(&lastfrag->buf,nextfrag->buf);
  335.         nextfrag->buf = NULLBUF;
  336.         lastfrag->last = nextfrag->last;
  337.  
  338.         /* Finally unlink and delete the now unneeded nextfrag */
  339.         lastfrag->next = nextfrag->next;
  340.         if(nextfrag->next != NULLFRAG)
  341.             nextfrag->next->prev = lastfrag;
  342.         freefrag(nextfrag);
  343.         break;
  344.     }
  345.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  346.         && rp->length != 0){
  347.         /* We've gotten a complete datagram, so extract it from the
  348.          * reassembly buffer and pass it on.
  349.          */
  350.         bp = rp->fraglist->buf;
  351.         rp->fraglist->buf = NULLBUF;
  352.         /* Tell IP the entire length */
  353.         ip->length = rp->length + (IPLEN + ip->optlen);
  354.         free_reasm(rp);
  355.         ipReasmOKs++;
  356.         return bp;
  357.     } else
  358.         return NULLBUF;
  359. }
  360. /* Arrange for receipt of raw IP datagrams */
  361. struct raw_ip *
  362. raw_ip(protocol,r_upcall)
  363. int protocol;
  364. void (*r_upcall)__ARGS((struct raw_ip *));
  365. {
  366.     register struct raw_ip *rp;
  367.  
  368.     rp = (struct raw_ip *)callocw(1,sizeof(struct raw_ip));
  369.     rp->protocol = protocol;
  370.     rp->r_upcall = r_upcall;
  371.     rp->next = Raw_ip;
  372.     Raw_ip = rp;
  373.     return rp;
  374. }
  375. /* Free a raw IP descriptor */
  376. void
  377. del_ip(rpp)
  378. struct raw_ip *rpp;
  379. {
  380.     struct raw_ip *rplast = NULLRIP;
  381.     register struct raw_ip *rp;
  382.  
  383.     /* Do sanity check on arg */
  384.     for(rp = Raw_ip;rp != NULLRIP;rplast=rp,rp = rp->next)
  385.         if(rp == rpp)
  386.             break;
  387.     if(rp == NULLRIP)
  388.         return;    /* Doesn't exist */
  389.  
  390.     /* Unlink */
  391.     if(rplast != NULLRIP)
  392.         rplast->next = rp->next;
  393.     else
  394.         Raw_ip = rp->next;
  395.     /* Free resources */
  396.     free_q(&rp->rcvq);
  397.     free((char *)rp);
  398. }
  399.  
  400. static struct reasm *
  401. lookup_reasm(ip)
  402. struct ip *ip;
  403. {
  404.     register struct reasm *rp;
  405.     struct reasm *rplast = NULLREASM;
  406.  
  407.     for(rp = Reasmq;rp != NULLREASM;rplast=rp,rp = rp->next){
  408.         if(ip->id == rp->id && ip->source == rp->source
  409.          && ip->dest == rp->dest && ip->protocol == rp->protocol){
  410.             if(rplast != NULLREASM){
  411.                 /* Move to top of list for speed */
  412.                 rplast->next = rp->next;
  413.                 rp->next = Reasmq;
  414.                 Reasmq = rp;
  415.             }
  416.             return rp;
  417.         }
  418.  
  419.     }
  420.     return NULLREASM;
  421. }
  422. /* Create a reassembly descriptor,
  423.  * put at head of reassembly list
  424.  */
  425. static struct reasm *
  426. creat_reasm(ip)
  427. register struct ip *ip;
  428. {
  429.     register struct reasm *rp;
  430.  
  431.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  432.         return rp;    /* No space for descriptor */
  433.     rp->source = ip->source;
  434.     rp->dest = ip->dest;
  435.     rp->id = ip->id;
  436.     rp->protocol = ip->protocol;
  437.     set_timer(&rp->timer,ipReasmTimeout * 1000L);
  438.     rp->timer.func = ip_timeout;
  439.     rp->timer.arg = rp;
  440.  
  441.     rp->next = Reasmq;
  442.     Reasmq = rp;
  443.     return rp;
  444. }
  445.  
  446. /* Free all resources associated with a reassembly descriptor */
  447. static void
  448. free_reasm(r)
  449. struct reasm *r;
  450. {
  451.     register struct reasm *rp;
  452.     struct reasm *rplast = NULLREASM;
  453.     register struct frag *fp;
  454.  
  455.     for(rp = Reasmq;rp != NULLREASM;rplast = rp,rp=rp->next)
  456.         if(r == rp)
  457.             break;
  458.     if(rp == NULLREASM)
  459.         return;    /* Not on list */
  460.  
  461.     stop_timer(&rp->timer);
  462.     /* Remove from list of reassembly descriptors */
  463.     if(rplast != NULLREASM)
  464.         rplast->next = rp->next;
  465.     else
  466.         Reasmq = rp->next;
  467.  
  468.     /* Free any fragments on list, starting at beginning */
  469.     while((fp = rp->fraglist) != NULLFRAG){
  470.         rp->fraglist = fp->next;
  471.         free_p(fp->buf);
  472.         free((char *)fp);
  473.     }
  474.     free((char *)rp);
  475. }
  476.  
  477. /* Handle reassembly timeouts by deleting all reassembly resources */
  478. static void
  479. ip_timeout(arg)
  480. void *arg;
  481. {
  482.     register struct reasm *rp;
  483.  
  484.     rp = (struct reasm *)arg;
  485.     free_reasm(rp);
  486.     ipReasmFails++;
  487. }
  488. /* Create a fragment */
  489. static struct frag *
  490. newfrag(offset,last,bp)
  491. int16 offset,last;
  492. struct mbuf *bp;
  493. {
  494.     struct frag *fp;
  495.  
  496.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  497.         /* Drop fragment */
  498.         free_p(bp);
  499.         return NULLFRAG;
  500.     }
  501.     fp->buf = bp;
  502.     fp->offset = offset;
  503.     fp->last = last;
  504.     return fp;
  505. }
  506. /* Delete a fragment, return next one on queue */
  507. static void
  508. freefrag(fp)
  509. struct frag *fp;
  510. {
  511.     free_p(fp->buf);
  512.     free((char *)fp);
  513. }
  514.  
  515. #ifndef UNIX
  516.  
  517. /* In red alert mode, blow away the whole reassembly queue. Otherwise crunch
  518.  * each fragment on each reassembly descriptor
  519.  */
  520. void
  521. ip_garbage(red)
  522. int red;
  523. {
  524.     struct reasm *rp,*rp1;
  525.     struct frag *fp;
  526.     struct raw_ip *rwp;
  527.  
  528.     /* Run through the reassembly queue */
  529.     for(rp = Reasmq;rp != NULLREASM;rp = rp1){
  530.         rp1 = rp->next;
  531.         if(red){
  532.             free_reasm(rp);
  533.         } else {
  534.             for(fp = rp->fraglist;fp != NULLFRAG;fp = fp->next){
  535.                 mbuf_crunch(&fp->buf);
  536.             }
  537.         }
  538.     }
  539.     /* Run through the raw IP queue */
  540.     for(rwp = Raw_ip;rwp != NULLRIP;rwp = rwp->next)
  541.         mbuf_crunch(&rwp->rcvq);
  542. }
  543.  
  544. #endif
  545.